#include <SPI.h>
#include <Ethernet.h>
#include <_OneWire.h>

//-------------------------------------------------------------------------------------------------
#define HOME

//-------------------------------------------------------------------------------------------------
// externe globale Variable:
extern long g_InfoNr;

//-------------------------------------------------------------------------------------------------
// globale Variable:
char g_Formkey[] = "dGlvTmlxTFAzZi0tOExOVVpIT1phdFE6MQ"; //Replace with your Key
byte g_Mac[] = {0x90,0xA2,0xDA,0x00,0x55,0x8D};  //Replace with your Ethernet shield MAC
int g_Led13 = 13;

#ifdef HOME
// Zuhaus
IPAddress g_Ip(192,168,2,12);
IPAddress g_Gateway(192,168,2,1);
IPAddress g_Subnet(255,255,255,0);
IPAddress g_Dns(192,168,2,1);
#else
// Gschäft
IPAddress g_Ip(192,168,198,8);
IPAddress g_Gateway(192,168,198,10);
IPAddress g_Subnet(255,255,255,0);
IPAddress g_Dns(192,168,198,1);
#endif

//IPAddress g_Server(209,85,229,101); // Google http://209.85.229.101
//IPAddress g_Server(74,125,39,104); // Google http://74.125.39.104
//IPAddress g_Server(173,194,112,184); // Google http://173.194.112.184
IPAddress g_Server(173,194,112,134); // Google http://173.194.112.134
EthernetClient g_EthernetClient;

unsigned long g_TimeAll_akt;
unsigned long g_TimeAll_old;
unsigned long g_TimeAll_dif;
unsigned long g_TimeWww_akt;
unsigned long g_TimeWww_old;
unsigned long g_TimeWww_dif;
unsigned long g_CrcAdrErrCnt;
unsigned long g_CrcDatErrCnt;
char g_StrData[500];
char g_StrTime[300];
char g_StrTmp[20];
unsigned long l_CntNr;
unsigned long l_CntError;
unsigned int l_ii;
char g_Char;
unsigned long g_InputCnt;
double g_Celsius;
double g_Temp1, g_Temp2;
unsigned int g_TempNr;
char g_StrTemp1[20];
char g_StrTemp2[20];
OneWire  g_Ds(10);  // on pin 10
unsigned char g_Gefunden;

//-------------------------------------------------------------------------------------------------
void setup()
{
  pinMode(g_Led13, OUTPUT);     
  l_CntNr = 0;
  l_CntError = 0;
  g_CrcAdrErrCnt = 0;
  g_CrcDatErrCnt = 0;
  g_InputCnt = 0;
  g_Celsius = 0.0;
  g_TempNr = 0;
  g_Gefunden = 0;
  
  Serial.begin(19200);
  //Serial.begin(57600);
  while (!Serial)
  {
   ; // wait for serial port to connect. Needed for Leonardo only
  }
  delay(1000);
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("SetupBeginn:-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-):-)");
  Serial.print("Start Arduino BF! -> ");
#ifdef HOME
  Serial.println("Zuhause");
#else
  Serial.println("nicht Zuhause");
#endif
  
  g_TimeAll_akt = millis();
  g_TimeAll_old = g_TimeAll_akt;
  g_TimeAll_dif = g_TimeAll_akt - g_TimeAll_old;
  g_TimeWww_dif = 0;
  
  TimeStringOut();
  
  Ram_TableDisplay();
  
  Serial.println("SetupEnde*********************************************************************");
}

//-------------------------------------------------------------------------------------------------
void loop()
{
  //.......................................................
  // Vorarbeit
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("");
  Serial.println("LoopBeginn--------------------------------------------------------------------");

  //.......................................................
  // Temperaturen Auslesen:
  Serial.println("Temperatursensoren auslesen...");
  strcpy(g_StrTemp1,"xxx");
  strcpy(g_StrTemp2,"yyy");
  while(GetTemp(g_TempNr,g_Celsius))
  {
    if(g_TempNr == 0)
    {
      g_Temp1 = 0.0;
      ftoa(g_StrTemp1,g_Temp1,3);
      g_Temp2 = 0.0;
      ftoa(g_StrTemp2,g_Temp2,3);
      Serial.println("Kein Temperaturfühler gefunden bzw. Fehler");
      g_Gefunden = 0;
    }
    if(g_TempNr == 1)
    {
      g_Temp1 = g_Celsius;
      ftoa(g_StrTemp1,g_Temp1,3);
      Serial.print("g_TempNr=1, "),Serial.print("Temperatur(C) = "), Serial.println(g_StrTemp1);
      g_Gefunden++;
    }
    if(g_TempNr == 2)
    {
      g_Temp2 = g_Celsius;
      ftoa(g_StrTemp2,g_Temp2,3);
      Serial.print("g_TempNr=2, "),Serial.print("Temperatur(C) = "), Serial.println(g_StrTemp2);
      g_Gefunden++;
    }
  }
  if (2 == g_Gefunden)
  {
    g_Gefunden = 0;
    
    l_CntNr++;
  
    EthernetStart();
    
    TimeStringOut();
  
    //.......................................................
    // Daten an Google schicken:
    if (g_EthernetClient.connected())
    {
      Serial.println("EthernetClient.connected = Ja");
  
      // Daten Schreiben:  
      sprintf(g_StrData,"%s%ld%s%ld%s%s%s%ld%s%ld%s%s%s%s%s%lu%s%lu%s"
        ,"entry.0.single="
        ,l_CntNr
        ,"&entry.1.single="
        ,g_TimeAll_akt
        ,"&entry.2.single="
        ,g_StrTmp
        ,"&entry.3.single="
        ,g_TimeAll_dif
        ,"&entry.4.single="
        ,g_TimeWww_dif
        ,"&entry.5.single="
        ,g_StrTemp1 // analogRead(A0)
        ,"&entry.6.single="
        ,g_StrTemp2 // analogRead(A1)
        ,"&entry.7.single="
        ,g_CrcAdrErrCnt// Checksumfehler Adresse
        ,"&entry.8.single="
        ,g_CrcDatErrCnt// Checksumfehler Adresse
        ,"&submit=Submit"
        );
    
      digitalWrite(g_Led13, HIGH);   // turn the LED on (HIGH is the voltage level)
      
      g_EthernetClient.print("POST /formResponse?formkey=");
      g_EthernetClient.print(g_Formkey);
      g_EthernetClient.println("&ifq HTTP/1.1");
      g_EthernetClient.println("Host: spreadsheets.google.com");
      g_EthernetClient.println("Content-Type: application/x-www-form-urlencoded");
      g_EthernetClient.println("Connection: close");
      g_EthernetClient.print("Content-Length: ");
      g_EthernetClient.println(strlen(g_StrData));
      g_EthernetClient.println();
      g_EthernetClient.println(g_StrData);
  
      Serial.println("ToWeb((((((((((((((((((((((((((((((((((((((((((");
      Serial.print("POST /formResponse?formkey=");
      Serial.print(g_Formkey);
      Serial.println("&ifq HTTP/1.1");
      Serial.println("Host: spreadsheets.google.com");
      Serial.println("Content-Type: application/x-www-form-urlencoded");
      Serial.println("Connection: close");
      Serial.print("Content-Length: ");
      Serial.println(strlen(g_StrData));
      Serial.println();
      Serial.println(g_StrData);
      Serial.println(")))))))))))))))))))))))))))))))))))))))))))))))");
  
      Serial.println("Warte: 2 Sek. vom Senden an www bis zur Abfrage der Rückdaten");
      delay(2000);
      
      Serial.println("FromWeb[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[");
      g_InputCnt = 0;
      while(g_EthernetClient.available())
      {
        g_InputCnt++;
        if (g_InputCnt > 2000)
          break;
        g_Char = g_EthernetClient.read();
        Serial.print(g_Char);
        //delay(10); // 20130905 BF, etwas warten, falls die Zeichen langsam kommen
      }
      Serial.println();
      Serial.println("]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
      
      digitalWrite(g_Led13, LOW);    // turn the LED off by making the voltage LOW
      
    } else
    {
      Serial.println("EthernetClient.connected = Nein");
      Serial.println("ToWeb((((((((((((((((((((((((((((((((((((((((((");
      Serial.println(")))))))))))))))))))))))))))))))))))))))))))))))");
      Serial.println("FromWeb[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[");
      Serial.println("]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
    }
  
    //.......................................................
    // Abschluss:
    Serial.println("Warte: 5 Sek. bis EthernetStop");
    delay(5000);
    EthernetStop();
  
    Serial.println("Wait: Bis zum naechsten Senden an das www");
    Serial.println("...............:::::");
    for (l_ii=0;l_ii<15;l_ii++)
    {
      Serial.print(".");
      digitalWrite(g_Led13, HIGH);
      delay(50);
      digitalWrite(g_Led13, LOW);
      delay(950);
    }  
    for (l_ii=0;l_ii<5;l_ii++)
    {
      Serial.print(":");
      digitalWrite(g_Led13, HIGH);
      delay(50);
      digitalWrite(g_Led13, LOW);
      delay(50);
      digitalWrite(g_Led13, HIGH);
      delay(50);
      digitalWrite(g_Led13, LOW);
      delay(850);
    }  
    Serial.println();
  
    g_TimeAll_old = g_TimeAll_akt;
    g_TimeAll_akt = millis();
    g_TimeAll_dif = g_TimeAll_akt - g_TimeAll_old;
  } // Ende Temperatursensor gefunden
  
} // Ende: loop


//-------------------------------------------------------------------------------------------------
// start the Ethernet connection:
boolean EthernetStart()
{
  Serial.println("Ethernet.begin(MacAdresse,...)");

  //if (Ethernet.begin(g_Mac) == 0){Serial.println("Failed to configure Ethernet using DHCP");for(;;);}
  Ethernet.begin(g_Mac,g_Ip);
  //Ethernet.begin(g_Mac,g_Ip,g_Dns);
  //Ethernet.begin(g_Mac,g_Ip,g_Dns,g_Gateway);
  //Ethernet.begin(g_Mac,g_Ip,g_Dns,g_Gateway,g_Subnet);
  
  // give the Ethernet shield two second to initialize:
  Serial.println("Warte: 1. Sek. fuer das Ethernet shield zur Initialisierung");
  delay(1000);

  Serial.print("Client verbindet zum Server, EthernetClient.connect -> ");

  g_TimeWww_akt = millis();
  g_TimeWww_old = g_TimeWww_akt;
  g_TimeWww_dif = g_TimeWww_akt - g_TimeWww_old;

#ifdef HOME
  if (g_EthernetClient.connect(g_Server, 80))
#else
  if (g_EthernetClient.connect(g_Server, 8080))
#endif
  {
    g_TimeWww_old = g_TimeWww_akt;
    g_TimeWww_akt = millis();
    g_TimeWww_dif = g_TimeWww_akt - g_TimeWww_old;

    Serial.print("succeed, Nr.-> ");
  } else
  {
    g_TimeWww_old = g_TimeWww_akt;
    g_TimeWww_akt = millis();
    g_TimeWww_dif = g_TimeWww_akt - g_TimeWww_old;

    Serial.print("failed, Nr.-> ");
  }

  Serial.println(g_InfoNr);

  Serial.print("connecting (while(!EthernetClient)) -> ");
  while(!g_EthernetClient)
  {
    Serial.print(".");
    digitalWrite(g_Led13, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(200);               // wait for a second
    digitalWrite(g_Led13, LOW);    // turn the LED off by making the voltage LOW
    delay(200);               // wait for a second
    
    l_CntError++;
    if (l_CntError >= 25)
    {
      Serial.println("!");
      break;
    }
  }
  if (l_CntError < 25)
    Serial.println("x");
  l_CntError = 0;

#ifdef HOME
  Serial.print("EthernetClient(Zuhause) -> ");
#else
  Serial.print("EthernetClient(nicht Zuhause) -> ");
#endif
  if (g_EthernetClient)
  {
    Serial.println("connected");
  } else
  {
    Serial.println("connection failed");
  }
  
  Serial.print("Ethernet.localIP -> ");
  Serial.println(Ethernet.localIP());
  
} // Ende: EthernetStart


//-------------------------------------------------------------------------------------------------
// start the Ethernet connection:
boolean EthernetStop()
{
  if (1)//(g_EthernetClient.connected())
  {
    Serial.print("EthernetClient Stop, Nr.-> ");
    g_EthernetClient.stop();
    Serial.println(g_InfoNr);
  }else
  {
    Serial.println("EthernetClient Stop nicht noetig, da nicht connected");
  }
} // Ende: EthernetStop


//-------------------------------------------------------------------------------------------------
// start the Ethernet connection:
boolean TimeStringOut()
{ 
  TimeMsToString(g_TimeAll_akt,g_StrTmp);

  sprintf(g_StrTime,"Zeit: l_CntNr: %ld; g_TimeAll_akt: %ld(ms) -> %s; g_TimeAll_dif: %ld(ms); g_TimeWww_dif: %ld(ms)"
    ,l_CntNr
    ,g_TimeAll_akt
    ,g_StrTmp
    ,g_TimeAll_dif
    ,g_TimeWww_dif
    );
  
  Serial.println(g_StrTime);

  return true;
} // Ende: TimeStringOut


//-------------------------------------------------------------------------------------------------
// start the Ethernet connection:
boolean TimeMsToString(unsigned long a_Ms, char a_Str[])
{
  unsigned long l_time, l_ms, l_s, l_m, l_h, l_d;
  l_time = a_Ms;
  
  l_ms = l_time % 1000;
  l_time /= 1000; // now it is seconds
  l_s = l_time % 60;
  l_time /= 60; // now it is minutes
  l_m = l_time % 60;
  l_time /= 60; // now it is hours
  l_h = l_time % 24;
  l_time /= 24; // now it is days
  //l_d = ((l_time + 4) % 7) + 1;  // Sunday is day 1 
  l_d = l_time;
  
  sprintf(a_Str,"%ld,%ld:%ld:%ld.%ld",l_d,l_h,l_m,l_s,l_ms);
  
  return true;
} // Ende: TimeMsToString


//-------------------------------------------------------------------------------------------------
boolean GetTemp(unsigned int &a_Nr, double &a_Celsius)
{
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  uint8_t l_cks;
  
  a_Celsius = 0.0;
  
  if ( !g_Ds.search(addr)) {
    Serial.println("No more addresses.");
    Serial.println();
    g_Ds.reset_search();
    delay(1000);//250);
    a_Nr = 0;
    return false;
  }
  a_Nr++;
  
  Serial.print("ROM =");
  for( i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }

  l_cks = OneWire::crc8(addr, 7);

  Serial.print(" CRC (Adress)=");
  Serial.print(l_cks, HEX);
  Serial.println();

  if (l_cks != addr[7]) {
      Serial.println("CRC (Adress) is not valid!");
      g_Ds.reset_search();
      delay(1000);//250);
      a_Nr = 0;
      g_CrcAdrErrCnt++;
      return false;
  }
 
  // the first ROM byte indicates which chip
  switch (addr[0]) {
    case 0x10:
      Serial.println("  Chip = DS18S20");  // or old DS1820
      type_s = 1;
      break;
    case 0x28:
      Serial.println("  Chip = DS18B20");
      type_s = 0;
      break;
    case 0x22:
      Serial.println("  Chip = DS1822");
      type_s = 0;
      break;
    default:
      Serial.println("Device is not a DS18x20 family device.");
      g_Ds.reset_search();
      delay(1000);//250);
      a_Nr = 0;
      return false;
  } 

  g_Ds.reset();
  g_Ds.select(addr);
  g_Ds.write(0x44,1);         // start conversion, with parasite power on at the end
  
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a g_Ds.depower() here, but the reset will take care of it.
  
  present = g_Ds.reset();
  g_Ds.select(addr);    
  g_Ds.write(0xBE);         // Read Scratchpad

  Serial.print("  Data = ");
  Serial.print(present,HEX);
  Serial.print(" ");
  for ( i = 0; i < 9; i++) {           // we need 9 bytes
    data[i] = g_Ds.read();
    Serial.print(data[i], HEX);
    Serial.print(" ");
  }
  l_cks = OneWire::crc8(data, 8);

  Serial.print(" CRC (Data)=");
  Serial.print(l_cks, HEX);
  Serial.println();

  if (l_cks != data[8]) {
      Serial.println("CRC (Data) is not valid!");
      g_Ds.reset_search();
      delay(1000);//250);
      a_Nr = 0;
      g_CrcDatErrCnt++;
      return false;
  }

  // convert the data to actual temperature

  unsigned int raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // count remain gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw << 3;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
    // default is 12 bit resolution, 750 ms conversion time
  }
  a_Celsius = (double)raw / 16.0;
  
  return true;
}

//-------------------------------------------------------------------------------------------------
char *ftoa(char *a, double f, int precision)
{
  long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
  
  char *ret = a;
  long heiltal = (long)f;
  itoa(heiltal, a, 10);
  while (*a != '\0') a++;
  *a++ = ',';
  long desimal = abs((long)((f - heiltal) * p[precision]));
  itoa(desimal, a, 10);
  return ret;
}

//************************************************************************
//*	http://www.nongnu.org/avr-libc/user-manual/malloc.html
//*	thanks to John O for the pointer to this info and the insperation to do it
void	Ram_TableDisplay(void) 
{
char stack = 1;
extern char *__data_start;
extern char *__data_end;

extern char *__bss_start;
extern char *__bss_end;
//extern char *__brkval;
extern char *__heap_start;
extern char *__heap_end;
//extern char *__malloc_heap_end;
//extern size_t __malloc_margin;


	int	data_size	=	(int)&__data_end - (int)&__data_start;
	int	bss_size	=	(int)&__bss_end - (int)&__data_end;
	int	heap_end	=	(int)&stack - (int)&__malloc_margin;
//	int	heap_size	=	(int)__brkval - (int)&__bss_end;
	int	heap_size	=	heap_end - (int)&__bss_end;
	int	stack_size	=	RAMEND - (int)&stack + 1;
	int	available	=	(RAMEND - (int)&__data_start + 1);
	
	available	-=	data_size + bss_size + heap_size + stack_size;

	Serial.print("+----------------+  __data_start  =");	Serial.println((int)&__data_start);
	Serial.print("+      data      +");						Serial.println();
	Serial.print("+    variables   +  data_size     =");	Serial.println(data_size);
	Serial.print("+                +");						Serial.println();
	Serial.print("+----------------+  __data_end    =");	Serial.println((int)&__data_end);
	Serial.print("+----------------+  __bss_start   =");	Serial.println((int)&__bss_start);
	Serial.print("+       bss      +");						Serial.println();
	Serial.print("+    variables   +  bss_size      =");	Serial.println(bss_size);
	Serial.print("+                +");						Serial.println();
	Serial.print("+----------------+  __bss_end     =");	Serial.println((int)&__bss_end);
	Serial.print("+----------------+  __heap_start  =");	Serial.println((int)&__heap_start);
	Serial.print("+                +");						Serial.println();
	Serial.print("+       heap     +  heap_size     =");	Serial.println(heap_size);
	Serial.print("+                +");						Serial.println();
	Serial.print("+----------------+  heap_end      =");	Serial.println(heap_end);
	Serial.print("+----------------+  Current STACK =");	Serial.println((int)&stack);
	Serial.print("+                +");						Serial.println();
	Serial.print("+      stack     +  stack_size    =");	Serial.println(stack_size);
	Serial.print("+                +");						Serial.println();
	Serial.print("+----------------+  RAMEND        =");	Serial.println(RAMEND);

	Serial.print("available =");
	Serial.println(available);
}

